package com.dingreading.cloud.admin.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.dingreading.cloud.admin.dto.ShopCartDto;
import com.dingreading.cloud.admin.dto.ShopCartSendDto;
import com.dingreading.cloud.admin.dto.ShopCartStatDto;
import com.dingreading.cloud.admin.entity.ShopCart;
import com.dingreading.cloud.admin.entity.table.ShopCartTableDef;
import com.dingreading.cloud.admin.mapper.ShopCartMapper;
import com.dingreading.cloud.admin.service.ShopCartService;
import com.dingreading.cloud.common.util.*;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryColumn;
import com.mybatisflex.core.query.QueryCondition;
import com.mybatisflex.core.query.QueryMethods;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Row;
import com.mybatisflex.core.update.UpdateChain;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.dingreading.cloud.admin.entity.table.OrderFormTableDef.orderForm;

/**
 * 服务层实现。
 *
 * @author Administrator
 * @since 2023-11-22
 */
@Service
public class ShopCartServiceImpl extends BaseServiceImpl<ShopCartMapper, ShopCart, ShopCartTableDef> implements ShopCartService {

    @Override
    protected ShopCartTableDef getTable() {
        return ShopCartTableDef.shopCart;
    }

    @Resource
    private ShopCartMapper shopCartMapper;

    @Override
    public Page<ShopCartSendDto> outPageListV2(PageUtil pageUtil, String keyword, Integer stockOutMethod, Integer status) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.stockOutMethod.eq(stockOutMethod))
                .and(table.code.isNotNull());
        if (StringUtils.isNotBlank(keyword)) {
            condition.and(table.goodsName.like(keyword)
                    .or(table.goodsTypeName.like(keyword))
                    .or(table.code.like(keyword))
                    .or(orderForm.storeName.like(keyword))
                    .or(orderForm.phone.like(keyword))
                    .or(orderForm.name.like(keyword))
            );
        }
        if (status != null)
            condition.and(table.status.eq(status));
        else
            condition.and(table.status.in(EnumType.ShopCart.PAYED.getType(), EnumType.ShopCart.SEND.getType()));


        QueryWrapper wrapper = QueryWrapper.create()
                .select(getShopCarDto())
                .from(table)
                .leftJoin(orderForm).on(table.code.eq(orderForm.code))
                .where(condition)
                .orderBy(table.payTimes.desc());

        return getMapper().paginateAs(Page.of(pageUtil.getPage(), pageUtil.getRows()), wrapper, ShopCartSendDto.class);
    }

    private QueryColumn[] getShopCarDto() {
        return new QueryColumn[]{
                table.id.as("shopCartId"), table.goodsId, table.goodsName,
                table.goodsTypeId, table.goodsTypeName, table.img, table.status, table.statusName, table.price, table.weight, table.totalWeight,
                table.buyNum, table.code, table.unitPrice, table.type, table.storeUid, table.staffUid,
                table.realStatus, table.addTime, table.payTimes, table.unit, table.paymentMethod, table.stockOutMethod,
                orderForm.storeName, orderForm.phone, orderForm.address, orderForm.name, table.outRemark, table.comboType
        };
    }


    @Override
    public int deleteByStaffIdAndCode(String staffUid, String code) {
        QueryCondition condition = QueryCondition.createEmpty();
        if (staffUid != null)
            condition.and(table.staffUid.eq(staffUid));
        condition.and(table.code.eq(code))
                .and(table.status.notIn(EnumType.ShopCart.PAYED.getType(), EnumType.ShopCart.SEND.getType(), EnumType.ShopCart.REFUND.getType()));
        return getMapper().deleteByCondition(condition);
    }

    @Override
    public List<ShopCart> getByCode(String staffUid, String code) {
        QueryCondition condition = QueryCondition.createEmpty();
        if (staffUid != null)
            condition.and(table.staffUid.eq(staffUid));
        condition.and(table.code.eq(code));
        return getMapper().selectListByCondition(condition);
    }

    @Override
    public List<ShopCart> getByCodes(String staffUid, List<String> code) {
        QueryCondition condition = QueryCondition.createEmpty();
        if (staffUid != null)
            condition.and(table.staffUid.eq(staffUid));
        condition.and(table.code.in(code));

        return getMapper().selectListByCondition(condition);
    }

    @Override
    public long getStaffShopCartCount(String storeUid, String staffUid, int type) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.storeUid.eq(storeUid))
                .and(table.staffUid.eq(staffUid))
                .and(table.type.eq(type))
                // 未付款且不是订单
                .and(table.status.eq(EnumType.ShopCart.WAIT_CONFIRM.getType()))
                .and(table.code.isNull())
                .and(table.mainComboType.eq(0).or(table.mainComboType.eq(1).and(table.comboType.eq(1))));

        return getMapper().selectCountByCondition(condition);
    }

    @Override
    public boolean cancelShopCarts(String staffUid, String code) {
        QueryCondition condition = QueryCondition.createEmpty();
        if (StringUtils.isNotBlank(staffUid))
            condition.and(table.staffUid.eq(staffUid));
        condition.and(table.code.eq(code))
                .and(table.status.in(EnumType.ShopCart.WAIT_CONFIRM.getType(), EnumType.ShopCart.WAIT_PAY.getType()));

        return UpdateChain.of(ShopCart.class)
                .set(table.status, EnumType.ShopCart.CANCEL.getType())
                .set(table.statusName, EnumType.ShopCart.CANCEL.getName())
                .where(condition)
                .update();
    }

    @Override
    public void cancelShopCartByGoodsId(Long goodsId) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.code.isNull())
                .and(table.status.eq(EnumType.ShopCart.WAIT_CONFIRM.getType()));

        condition.and(table.mainComboType.eq(0).and(table.goodsId.eq(goodsId))
                .or(table.comboType.eq(1).and(table.mainComboType.eq(1)).and(table.goodsId.eq(goodsId)))
                .or(table.comboType.eq(0).and(table.mainComboType.eq(1)).and(table.mainGoodsId.eq(goodsId)))
        );

        UpdateChain.of(ShopCart.class)
                .set(table.status, EnumType.ShopCart.CANCEL.getType())
                .set(table.statusName, EnumType.ShopCart.CANCEL.getName())
                .where(condition)
                .update();
    }

    @Override
    public void cancelShopCartByGoodsTypeId(Integer mainComboType, Long goodsTypeId) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.code.isNull())
                .and(table.status.eq(EnumType.ShopCart.WAIT_CONFIRM.getType()))
                .and(table.mainComboType.eq(mainComboType));
        if (mainComboType.equals(0)) {
            if (goodsTypeId != null)
                condition.and(table.goodsTypeId.eq(goodsTypeId));
        } else {
            if (goodsTypeId != null)
                condition.and(table.goodsTypeId.eq(goodsTypeId).or(table.mainGoodsTypeId.eq(goodsTypeId)));
        }

        UpdateChain.of(ShopCart.class)
                .set(table.status, EnumType.ShopCart.CANCEL.getType())
                .set(table.statusName, EnumType.ShopCart.CANCEL.getName())
                .where(condition)
                .update();
    }

    @Override
    public void confirmShopCart(String code) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.code.eq(code))
                .and(table.status.eq(EnumType.ShopCart.WAIT_CONFIRM.getType()));

        UpdateChain.of(ShopCart.class)
                .set(table.status, EnumType.ShopCart.WAIT_PAY.getType())
                .set(table.statusName, EnumType.ShopCart.WAIT_PAY.getName())
                .where(condition)
                .update();
    }

    @Override
    public boolean resumeShopCarts(String code, Integer status, String statusName) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.code.eq(code))
                .and(table.status.eq(EnumType.ShopCart.CANCEL.getType()));

        return UpdateChain.of(ShopCart.class)
                .set(table.status, status)
                .set(table.statusName, statusName)
                .where(condition)
                .update();
    }

    @Override
    public long getWaitOutCnt(String code) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.code.eq(code))
                .and(table.status.eq(EnumType.ShopCart.PAYED.getType()))
                // 可发货的商品
                .and(table.comboType.eq(0));

        return getMapper().selectCountByCondition(condition);
    }

    @Override
    public ShopCart getByCodeAndId(String code, Long id) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.code.eq(code))
                .and(table.id.eq(id));

        return getMapper().selectOneByCondition(condition);
    }

    @Override
    public boolean updateOutRemark(String code, Long id, String outRemark) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.id.eq(id))
                .and(table.code.eq(code));

        return UpdateChain.of(ShopCart.class)
                .set(table.outRemark, outRemark)
                .where(condition)
                .update();
    }

    @Override
    public boolean setOutOk(String code) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.status.eq(EnumType.ShopCart.PAYED.getType()))
                .and(table.code.eq(code));

        return UpdateChain.of(ShopCart.class)
                .set(table.status, EnumType.ShopCart.SEND.getType())
                .set(table.statusName, EnumType.ShopCart.SEND.getName())
                .where(condition)
                .update();
    }

    @Override
    public boolean setOutOk(String code, Long id, String outRemark) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.id.eq(id))
                .and(table.code.eq(code))
                .and(table.status.eq(EnumType.ShopCart.PAYED.getType()));

        return UpdateChain.of(ShopCart.class)
                .set(table.status, EnumType.ShopCart.SEND.getType())
                .set(table.statusName, EnumType.ShopCart.SEND.getName())
                .set(table.outRemark, outRemark)
                .where(condition)
                .update();
    }

    @Override
    public boolean revocationPayed(String code) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.code.eq(code))
                .and(table.status.eq(EnumType.ShopCart.PAYED.getType()));

        return UpdateChain.of(ShopCart.class)
                .set(table.status, EnumType.ShopCart.WAIT_PAY.getType())
                .set(table.statusName, EnumType.ShopCart.WAIT_PAY.getName())
                .where(condition)
                .update();
    }


    @Override
    public boolean revocationGiftShopCarts(String code, String staffUid, String staffName) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.code.eq(code))
                .and(table.status.eq(EnumType.ShopCart.PAYED.getType()));

        return UpdateChain.of(ShopCart.class)
                .set(table.status, EnumType.ShopCart.WAIT_CONFIRM.getType())
                .set(table.statusName, EnumType.ShopCart.WAIT_CONFIRM.getName())
                .set(table.lastStaffUid, NepUtil.nullToZero(staffUid))
                .set(table.lastStaffName, NepUtil.nullToZero(staffName))
                .where(condition)
                .update();
    }

    @Override
    public boolean haveGiftGoodsType(String storeUid, Long goodsId, Long goodsTypeId) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.storeUid.eq(storeUid))
                .and(table.goodsId.eq(goodsId))
                .and(table.goodsTypeId.eq(goodsTypeId))
                .and(table.type.eq(3))
                // 未付款且不是订单
                .and(table.status.eq(EnumType.ShopCart.WAIT_CONFIRM.getType()))
                .and(table.code.isNull());

        return exists(condition);
    }

    @Override
    public List<ShopCart> giftMainListByStoreUidAndStaffUid(String storeUid, String staffUid) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.storeUid.eq(storeUid))
                .and(table.staffUid.eq(staffUid))
                .and(table.type.eq(3))
                // 未付款且不是订单
                .and(table.status.eq(EnumType.ShopCart.WAIT_CONFIRM.getType()))
                .and(table.code.isNull())
                .and(table.mainComboType.eq(0).or(table.mainComboType.eq(1).and(table.comboType.eq(1))));

        QueryWrapper wrapper = QueryWrapper.create()
                .where(condition)
                .orderBy(table.freeDeliveryStatus.asc(), table.id.desc());

        return getMapper().selectListByQuery(wrapper);
    }

    @Override
    public List<ShopCart> giftMainRelationListByStoreUidAndStaffUid(String storeUid, String staffUid) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.storeUid.eq(storeUid))
                .and(table.staffUid.eq(staffUid))
                .and(table.type.eq(3))
                // 未付款且不是订单
                .and(table.status.eq(EnumType.ShopCart.WAIT_CONFIRM.getType()))
                .and(table.code.isNull())
                .and(table.mainComboType.eq(0).or(table.mainComboType.eq(1).and(table.comboType.eq(1))));

        QueryWrapper wrapper = QueryWrapper.create()
                .where(condition)
                .orderBy(table.freeDeliveryStatus.asc(), table.id.desc());

        return getMapper().selectListWithRelationsByQuery(wrapper);
    }

    @Override
    public long dropByStoreUidAndId(String storeUid, Long id, String shopCartUid) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.storeUid.eq(storeUid))
                .and(table.code.isNull())
                .and(table.status.notIn(EnumType.ShopCart.PAYED.getType(), EnumType.ShopCart.SEND.getType(), EnumType.ShopCart.REFUND.getType()))
                .and(table.id.eq(id).or(table.mainShopCartUid.eq(shopCartUid)))
        ;
        return getMapper().deleteByCondition(condition);
    }

    @Override
    public boolean getByTypeAndGoodsTypeId(int type, Long goodsTypeId) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.type.eq(type))
                .and(table.goodsTypeId.eq(goodsTypeId));

        return exists(condition);
    }

    @Override
    public boolean haveGoodsId(Long goodsId) {
        return exists(table.goodsId.in(goodsId));
    }

    @Override
    public boolean haveGoodsTypeId(Long goodsTypeId) {
        return exists(table.goodsTypeId.eq(goodsTypeId));
    }

    @Override
    public List<ShopCart> mainListAndChildListByCode(String code) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.code.eq(code));

        QueryWrapper wrapper = QueryWrapper.create()
                .where(condition)
                .orderBy(table.id.asc());
        return getMapper().selectListByQuery(wrapper);
    }


    @Override
    public List<ShopCart> childListByStoreUidAndStaffUidAndUidsAndCodeIsNull(String storeUid, String staffUid, List<String> mainShopCartUids) {
        QueryCondition condition = table.code.isNull()
                .and(table.status.eq(EnumType.ShopCart.WAIT_CONFIRM.getType()))
                .and(table.storeUid.eq(storeUid))
                .and(table.staffUid.eq(staffUid))
                .and(table.comboType.eq(0))
                .and(table.mainComboType.eq(1))
                .and(table.mainShopCartUid.in(mainShopCartUids));

        QueryWrapper wrapper = QueryWrapper.create()
                .where(condition);
        return getMapper().selectListWithRelationsByQuery(wrapper);
    }

    @Override
    public List<ShopCartDto> listByCodeAndComboType(String code, Integer comboType) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.code.eq(code))
                .and(table.comboType.eq(comboType));

        QueryWrapper wrapper = QueryWrapper.create()
                .where(condition)
                .orderBy(table.freeDeliveryStatus.asc(), table.mainComboType.asc(), table.id.asc(), table.stockOutMethod.asc());

        return getMapper().selectListByQueryAs(wrapper, ShopCartDto.class);
    }

    @Override
    public void updateFormInfo(List<String> shopCartUids, String code) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.status.eq(EnumType.ShopCart.WAIT_CONFIRM.getType()))
                .and(table.code.isNull())
                .and(table.uid.in(shopCartUids).or(table.mainShopCartUid.in(shopCartUids)));

        UpdateChain.of(ShopCart.class)
                .set(table.code, code)
                .where(condition)
                .update();
    }


    @Override
    public List<ShopCartSendDto> listToExpress(List<String> codes, Integer stockOutMethod) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.comboType.eq(0))
                .and(table.code.in(codes));
        if (stockOutMethod != null)
            condition.and(table.stockOutMethod.eq(stockOutMethod));

        QueryWrapper wrapper = QueryWrapper.create()
                .where(condition)
                .orderBy(table.freeDeliveryStatus.asc(), table.mainComboType.asc(), table.id.asc(), table.stockOutMethod.asc());

        return getMapper().selectListByQueryAs(wrapper, ShopCartSendDto.class);
    }

    @Override
    public int getWaitSendNum(Long goodsTypeId) {
        Integer waitSendNum = shopCartMapper.getWaitSendNum(goodsTypeId);
        return NepUtil.nullToZero(waitSendNum);
    }

    @Override
    public Map<Long, Integer> getWaitSendNum(List<Long> goodsTypeIds) {
        // 结果,默认值设置0
        Map<Long, Integer> map = new HashMap<>();
        for (Long goodsTypeId : goodsTypeIds) {
            map.put(goodsTypeId, 0);
        }
        List<JSONObject> list = shopCartMapper.getWaitSendNumList(goodsTypeIds);
        if (CollectionUtils.isNotEmpty(list)) {
            for (JSONObject jsonObject : list) {
                Long goodsTypeId = jsonObject.getLong("goodsTypeId");
                Integer cnt = jsonObject.getInteger("cnt");
                if (goodsTypeId != null && cnt != null) {
                    map.put(goodsTypeId, NepUtil.nullToZero(cnt));
                }
            }
        }
        return map;
    }

    @Override
    public Map<Long, Integer> getSoldNum(List<Long> goodsTypeIds, Integer storeType) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.status.in(1, 4))
                .and(table.goodsTypeId.in(goodsTypeIds));
        if (null != storeType) {
            if (storeType.equals(1)) {
                // 自营门店
                condition.and(table.corpUid.eq(AccountUtil.SELF_CORP_UID));
            } else if (storeType.equals(2)) {
                // 总部
                condition.and(table.corpUid.eq(AccountUtil.SELF_CORP_UID_T));
            } else {
                condition.and(table.corpUid.notIn(AccountUtil.SELF_CORP_UID, AccountUtil.SELF_CORP_UID_T));
            }
        }

        QueryWrapper wrapper = QueryWrapper.create()
                .select(QueryMethods.sum(table.buyNum).as("cnt"), table.goodsTypeId)
                .from(table)
                .where(condition)
                .groupBy(table.goodsTypeId);

        List<Row> list = getMapper().selectRowsByQuery(wrapper);

        Map<Long, Integer> map = new HashMap<>();
        for (Long goodsTypeId : goodsTypeIds) {
            map.put(goodsTypeId, 0);
        }
        if (CollectionUtils.isNotEmpty(list)) {
            for (Row row : list) {
                Long goodsTypeId = row.getLong("goods_type_id");
                Integer cnt = row.getInt("cnt");
                map.put(goodsTypeId, NepUtil.nullToZero(cnt));
            }
        }
        return map;
    }


    @Override
    public void updateUnitPrice(Long goodsTypeId, Double uPrice) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.goodsTypeId.eq(goodsTypeId))
                // 排除组合子商品
                .and(table.mainComboType.eq(0).or(table.mainComboType.eq(1).and(table.comboType.eq(1))))
                .and(table.status.in(EnumType.ShopCart.WAIT_CONFIRM.getType()))
                .and(table.code.isNull());

        UpdateChain.of(ShopCart.class)
                .set(table.unitPrice, uPrice)
                .set(table.price, table.buyNum.multiply(uPrice))
                .where(condition)
                .update();
    }

    @Override
    public List<ShopCart> saleListByGoodsTypeIdIn(List<Long> goodsTypeIds) {
        QueryCondition condition = table.goodsTypeId.in(goodsTypeIds)
                .and(table.status.in(1, 4));
        return getMapper().selectListByCondition(condition);
    }

    @Override
    public List<ShopCart> makeupList(List<String> codeList) {
        QueryCondition condition = table.corpUid.ne(AccountUtil.SELF_CORP_UID)
                .and(table.type.ne(3))
                .and(table.status.in(1, 2, 3))
                .and(table.code.isNotNull())
                .and(table.code.in(codeList));

        QueryWrapper wrapper = QueryWrapper.create()
                .where(condition);

        return getMapper().selectListWithRelationsByQuery(wrapper);
    }

    @Override
    public List<ShopCartStatDto> storeBuyGoodsStat(String beginDate, String endDate) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.payTimes.between(QueryFiledUtil.appendMin00(beginDate), QueryFiledUtil.appendMin24(endDate)))
                .and(table.status.in(EnumType.ShopCart.PAYED.getType(),EnumType.ShopCart.SEND.getType()))
                .and(table.comboType.eq(0));
        QueryWrapper wrapper = QueryWrapper.create()
                .where(condition)
                .orderBy(table.id.asc());
        return getMapper().selectListWithRelationsByQueryAs(wrapper, ShopCartStatDto.class);
    }

    @Override
    public List<ShopCart> listByDiscountPriceIsNUll() {
        QueryCondition condition = table.discountRate.isNotNull()
                .and(table.discountPrice.isNull());
        return getMapper().selectListByCondition(condition);
    }

    @Override
    public void updateDiscountPrice(Long id, double discountPrice) {
        UpdateChain.of(ShopCart.class)
                .set(table.discountPrice, discountPrice)
                .where(table.id.eq(id))
                .update();
    }

}
